<template>
    <div class="editor-container">
        <div ref="editorRef" class="editor" />
        <div class="font-size-model" v-show="showFontSize">
            {{ fontSize }}
        </div>
    </div>
</template>

<script setup>
import ace from "./aceEditor"
import { isArray } from "@vue/shared"

const emits = defineEmits(['update:modelValue'])

const minFontSize = 16
const maxFontSize = 32

const props = defineProps({
    modelValue: {
        type: String,
        default: ""
    },
    options: {
        type: Object,
        default: () => {
            return {
                lang: "text",
                theme: "chrome",
                fontSize: minFontSize,
                fontFamily: "Consolas",
                showPrintMargin: false,
                showGutter: true,
                highlightActiveLine: true,
                enableBasicAutocompletion: true,
                enableSnippets: true,
                enableLiveAutocompletion: true,
            }
        }
    },
    command: {
        type: [Array, Object],
        default: () => {
            return []
        }
    }
})

const editorRef = $ref(null)

const editor = $computed(() => {
    return ace.edit(editorRef)
})

const getSelection = () => {
    return editor.session.getTextRange(editor.getSelectionRange())
}

let showFontSize = $ref(false)
let timer = $ref(null)

const refreshTimer = () => {
    if (timer) clearTimeout(timer)
    showFontSize = true;
    timer = setTimeout(_ => {
        showFontSize = false
    }, 500)
}

let fontSize = $ref(props.options.fontSize || minFontSize)

watch(() => props.options.fontSize, (newVal) => { fontSize = newVal })

const aceOptions = $computed(() => {
    return {
        useWorker: props.options.useWorker || false,
        enableBasicAutocompletion: true,
        enableSnippets: true,
        enableLiveAutocompletion: true,
        theme: "ace/theme/" + (props.options.theme || 'chrome'),
        mode: "ace/mode/" + (props.options.lang || 'text'),
        tabSize: 2,
        showPrintMargin: false,
        fontSize: fontSize,
        readOnly: props.options.readOnly || false,
        wrap: props.options.wrap || "free",
    }
})

const checkUpperCase = (letter) => {
    return /[A-Z]/.test(letter)
}

const defaultCommand = [{
    name: "lowerOrUpperCase",
    bindKey: { win: "Ctrl-U", mac: "Ctrl-U" },
    exec: (editor) => {
        const range = editor.getSelectionRange()
        const text = editor.session.getTextRange(range)
        if (text) {
            checkUpperCase(text) ? editor.commands.commands.tolowercase.exec(editor) : editor.commands.commands.touppercase.exec(editor)
            setTimeout(() => {
                editor.selection.setRange(range)
            }, 10)
        }
    },
    readOnly: true
}, {
    name: "F1",
    bindKey: { win: "F1", mac: "F1" },
    exec: () => { },
    readOnly: true
}, {
    name: "F4",
    bindKey: { win: "F4", mac: "F4" },
    exec: () => {
        // console.log(editor.commands.commands)
        // editor.commands.commands.beautify.exec(editor)
    },
    readOnly: true
}, {
    name: "minus",
    bindKey: { win: "Ctrl--", mac: "Command--" },
    exec: () => {
        if (fontSize > minFontSize) {
            fontSize -= 1;
        }
        refreshTimer()
    },
    readOnly: true
}, {
    name: "add",
    bindKey: { win: "Ctrl-=", mac: "Command-=" },
    exec: () => {
        if (fontSize < maxFontSize) {
            fontSize += 1;
        }
        refreshTimer()
    },
    readOnly: true
}]

watchEffect(() => {
    editor.setOptions(aceOptions)
})

watch(
    () => props.modelValue,
    (newVal) => {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            if (newVal === editor.getValue()) return
            // const position = editor.getCursorPosition();
            editor.setValue(newVal)
            editor.clearSelection();
            // editor.moveCursorToPosition(position);
        })
    }, { immediate: true }
)

onMounted(() => {
    editor.on("change", () => {
        emits("update:modelValue", editor.getValue())
    })
    //快捷键
    for (let command of defaultCommand) {
        editor.commands.addCommand(command)
    }
    if (isArray(props.command)) {
        for (let command of props.command) {
            editor.commands.addCommand(command)
        }
    } else {
        editor.commands.addCommand(props.command)
    }
})

defineExpose({ getSelection })
</script>

<style scoped>
.editor {
    height: 100%;
    width: 100%;
}

.editor-container {
    position: relative;
    height: 100%;
    width: 100%;
}

.font-size-model {
    position: absolute;
    top: 0;
    left: 0;
    font-size: 40px;
    color: #6c6c6c;
    z-index: 99;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, .8);
}

.ace-chrome {
    background-color: transparent;
}

:deep(.ace-chrome .ace_gutter) {
    background-color: transparent;
    border-right: 1px solid rgba(0, 0, 0, .08);
}

:deep(.ace-chrome .ace_gutter-active-line) {
    background-color: rgba(0, 0, 0, .07);
}

:deep(.ace-chrome .ace_marker-layer .ace_selected-word) {
    background: rgb(253 253 253 / 40%);
    border: 1px solid rgba(200, 200, 250, .5);
}

:deep(.ace-chrome .ace_indent-guide) {
    opacity: .4 !important;
}
</style>